package com.pan.annotation.aspect;

import com.pan.annotation.RecordHistory;
import com.pan.dao.order1History.Order1HistoryDao;
import com.pan.dao.order2History.Order2HistoryDao;
import com.pan.entity.OperationOrder1History;
import com.pan.entity.OperationOrder2History;
import com.pan.entity.Result;
import com.pan.enume.EntityEnum;
import com.pan.enume.HistoryEnum;
import com.pan.enume.StatusLevel;
import com.pan.tools.ArrayTools;
import com.pan.tools.RedisTools;
import lombok.SneakyThrows;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Function;

@Aspect
@Component
public class RecordHistoryAspect {


    @Resource
    private RedisTools redisTools;

    @Pointcut("@annotation(com.pan.annotation.RecordHistory)")
    public void annotationCut(){}

    @AfterReturning(value = "annotationCut()",returning = "result")
    public void record(JoinPoint joinPoint,Result result) {
        if (result.getCode()!=200){
            return;
        }
        Object target =joinPoint.getTarget();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String methodName = methodSignature.getName();
        Class[] parameterTypes = methodSignature.getParameterTypes();

        Method targetMethod = methodSignature.getMethod();
//        try {
//            targetMethod = target.getClass().getMethod(methodName,parameterTypes);
//        } catch (NoSuchMethodException e) {
//            throw new RuntimeException(e);
//        }
        RecordHistory recordHistory = targetMethod.getAnnotation(RecordHistory.class);
        Object[] args = joinPoint.getArgs();
        String ticketName = recordHistory.ticketName();
        String idName = recordHistory.idName();
        String statusName = recordHistory.statusName();
        String[] parameterNames = methodSignature.getParameterNames();
        String ticket = (String) args[ArrayTools.indexOf(parameterNames,ticketName)];
        Long orderId =  (Long) args[ArrayTools.indexOf(parameterNames,idName)];
        Integer status = (Integer) args[ArrayTools.indexOf(parameterNames,statusName)];
        HistoryEnum historyEnum = recordHistory.value();
        Class historyType = historyEnum.getDaoClass();
        Timestamp nowTime = new Timestamp(System.currentTimeMillis());
        StatusLevel statusLevel = new StatusLevel();

        BiFunction<String,String,Long> getOperatorId = (role, userTicket) -> (Long)redisTools.hget(role+":"+userTicket,"id").getData();
        try {
            if (historyType ==  Order1HistoryDao.class){
                String role = statusLevel.get(EntityEnum.ORDER_1,status);
                Long operatorId = getOperatorId.apply(role,ticket);
                Order1HistoryDao dao = (Order1HistoryDao) historyType.newInstance();
                OperationOrder1History order1History = (OperationOrder1History) historyEnum.getHistoryType().newInstance();
                order1History.setOrder1Status(status)
                        .setCreateDate(nowTime)
                        .setOrderId(orderId)
                        .setRole(role.equals("admin")?0:1)
                        .setOperatorId(operatorId);
                dao.insert(order1History);
            }
            else {
                String role = statusLevel.get(EntityEnum.ORDER_2,status);
                Long operatorId = getOperatorId.apply(role,ticket);
                Order2HistoryDao dao = (Order2HistoryDao) historyType.newInstance();
                OperationOrder2History order2History = (OperationOrder2History) historyEnum.getHistoryType().newInstance();
                order2History.setOrder2Status(status)
                        .setCreateDate(nowTime)
                        .setOrder2Id(orderId)
                        .setRole(role.equals("user")?1:0)
                        .setOperatorId(operatorId);
                dao.insert(order2History);
            }
        } catch (InstantiationException | IllegalAccessException | NoSuchFieldException e) {
            throw new RuntimeException(e);
        }

    }

}
